#!/usr/bin/perl
#
#  Copyright (c) 1997-2009
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
#  http://www.polymake.de
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-------------------------------------------------------------------------------
#  $Project: polymake $$Id: polymake 9366 2009-10-18 22:25:53Z gawrilow $

use v5.8.1;
use POSIX;

package Polymake;

# global variables needed for the bootstrap
use vars qw($InstallTop $InstallArch $Arch $DeveloperMode);
my @addlibs;
BEGIN {
   require Cwd;
   $InstallTop=Cwd::abs_path( $0=~m%(?:^|/)[^/]+/[^/]+$% ? ($` || ".") : ".." );
   do "$InstallTop/support/locate_build_dir";
   die $@ if $@;
   if (defined $BuildDir) {
      $InstallArch=Cwd::abs_path($BuildDir);
   } else {
      die "build directory not found\nPlease run `make configure' or properly set the `Arch' environment variable.\n";
   }
   if ($^O eq "darwin") {
      unless (defined($FinkBase)) {
	 open my $CONF, "$BuildDir/conf.make" or die "can't read $BuildDir/conf.make: $!\n";
	 my $need_vars=2;
	 while (<$CONF>) {
	    if (/^\s*(FinkBase|Arch)\s*=\s*(\S+)/) {
	       $$1=$2;
	       last if ! --$need_vars;
	    }
	 }
      }
      push @addlibs, "$FinkBase/lib/perl5";
   }
   $DeveloperMode=1;
}

use lib "$InstallTop/perllib", "$InstallArch/perlx", @addlibs;

use Getopt::Long qw( GetOptions :config require_order bundling no_ignore_case );

my ($verbose, $script, $touch, $help, $tell_version);

if ( ! GetOptions( 'v+' => \$verbose, 'd+' => \$DebugLevel,
		   'n' => \$Polymake::Core::Scheduler::dry_run,
		   'A=s' => \$Polymake::Core::Shell::start_application,
		   'T=f' => \$Polymake::Core::Rule::timeout,
		   'script=s' => sub { $script=$_[1]; die "!FINISH\n" },
		   'touch' => \$touch, 'help' => \$help, 'version' => \$tell_version,
		   'reconfigure' => \$Polymake::Core::Customize::reconfigure,
		   'reconfigure-rules=s' => sub { collect_arglist(\@Polymake::Core::Application::reconfigure_rules, $_[1]) },
                 )
     #  --script --touch --help --version are mutually exclusive
     or defined($script)+$touch+$help+$tell_version > 1
     #  --help --version do not consume any additional args
     or $help+$tell_version && @ARGV
     #  -n is only applicable in compatibility mode
     or $Polymake::Core::Scheduler::dry_run && (defined($script) || @ARGV<2) ) {

   $!=1;
   die <<'.';
usage: polymake [-dv] [-A <application>] [-T <timeout>]
                [--reconfigure | --reconfigure-rules RULENAME ... ]
                [--script <script_file> [arg ...] | '<script>' | - ] |
                [-n] <file> <property|method> ... |
                --touch <file> ... | --help | --version
.
}

if ($help) {
   print STDERR <<'.';
usage: polymake [options] [arguments]
   called without arguments:
      start an interactive shell

   arguments may be one of the following:
      --help
         print this text and exit
      --version
         print the version number, copyright notice, and exit
      [--script] [application::]script_file
         execute the perl script in the file
         If application prefix is specified, this application is loaded
         and the script file is looked up in its script directory.
         Prefix none:: suppresses loading any applications before starting
         the script.
      --script [application::]script_file arguments ...
         execute the perl script in the file, passing the arguments in @ARGV
      'script text'
         interpret the string as a perl expression
      -
         read and execute the commands from the standard input

      file PROPERTY | METHOD [ ... ]
         the compatibility mode with polymake <= 2.3:
         read the object from the data file, print the properties or
         run the user methods

      function ARG ...
         simplified syntax for a user function call; arguments can be data files
         and numerical or string constants

      --touch file [ file ... ]
         read the files and write them out; useful for converting from
         earlier polymake versions

   options are:
      -A application_name
          start with this application, ignoring the $default_application and
          @start_applications settings
      -d  produce some debug output; can be repeated to increase the debug level
      -v  tell what's going on; can be repeated to increase the verbosity level.
          This is an obsolete option, please use custom variables $Verbose::*
          to gain more detailed control.

      --reconfigure
          rerun the autoconfiguration sections in all rule files
      --reconfigure-rules RULENAME ...
          rerun the autoconfiguration sections in the rule files matching RULENAME

      -n  `dry run' mode: show the production rules that would be applied to the
          object, but don't run any; only applicable to the compatibility mode

      -T sec
          set a time limit for the execution of production rules (currently broken)
.
   exit;
}

require Polymake;

sub release_date {
   my @date= '$Date: 2009-10-19 00:25:53 +0200 (Mon, 19 Oct 2009) $' =~ /(\d+)-(\d+)-(\d+)/;
   return POSIX::strftime("%B %d, %Y",0,0,12,$date[2],$date[1]-1,$date[0]-1900);
}

sub revision {
   my $rev='$Revision: 9366 $';
   return $rev =~ /:\s+(\d+)/;
}

sub greeting {
   "polymake version $Version, ",
   ($DeveloperMode ? ("rev. ", revision) : ("released on ", release_date)), <<'.';

Copyright (c) 1997-2009
Ewgenij Gawrilow, Michael Joswig (TU Darmstadt)
http://www.polymake.de

This is free software licensed under GPL; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.
}

# Getopt::Long does not allow to combine short option bundling with multi-value options
# Here is a work-around
sub collect_arglist {
   my $list=shift;
   @$list=@_;
   while (@ARGV && $ARGV[0] !~ /^-/) {
      push @$list, shift @ARGV;
   }
}

if ($tell_version) {
   print STDERR greeting;
   exit;
}

if ($verbose || $DebugLevel) {
   print STDERR "polymake version $Version\n";
}

if ($DebugLevel) {
   $Polymake::User::Verbose::rules=3;
   $Polymake::User::Verbose::cpp=2;
   assign_max($Polymake::User::Verbose::scheduler, $DebugLevel);
   if ($DebugLevel>1) {
      $Polymake::User::Verbose::external=1;
   }
}
if ($verbose) {
   assign_max($Polymake::User::Verbose::rules,$verbose);
   assign_max($Polymake::User::Verbose::scheduler,$verbose);
}

if ($touch) {
   Polymake::Core::Shell::touch_files(@ARGV);

} elsif (defined($script)) {
   Polymake::Core::Shell::run_script($script);

} elsif (@ARGV<=1) {
   if (@ARGV==0) {
      if (-t STDIN) {
	 ### interactive shell
	 Polymake::Core::Shell::run();
      } else {
	 die "can't run the interactive shell without terminal input\n";
      }

   } else {
      my $arg=shift;
      if ($arg eq "-") {
	 Polymake::Core::Shell::run_pipe(\*STDIN);
      } elsif ($arg !~ /[\s'"(){}\[\]]/) {
	 ### script file
	 Polymake::Core::Shell::run_script($arg);
      } else {
	 Polymake::Core::Shell::load_apps();
	 Polymake::Core::Shell::eval_expr($arg);
      }
   }
} else {
   Polymake::Core::Shell::load_apps();
   require Polymake::Core::Compat;
   eval {
      Polymake::User::Compat::execute(@ARGV);
   }
}
if ($@) {
   err_print($@);
   exit 1;
}

# to serve as a breakpoint in the perl debugger
sub stop_here { print STDERR "@_\n" if @_ }


# Local Variables:
# mode: perl
# c-basic-offset:3
# End:
